﻿/****************
* Authored by Zhuo "Wizcas" Chen
* 2018 © Wubi.fun all rights reserved
*****************/

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Wubi.Utils;

public class Block : MonoBehaviour 
{
    public static List<Block> __spawnedBlocks = new List<Block>(); //fixme
    const int FREE_LAYER = 8;
    const int SETTLED_LAYER = 9;

    #region Public Settings
    public string id;
    public AudioClip _pickUpSfx;
    public AudioClip _dropSuccSfx;
    public AudioClip _dropFailSfx;
    #endregion

    Vector3 _origPos;
    bool _isDestroying;
    int _layer;

    #region Properties
    BoxCollider _coll;
    new BoxCollider collider { get { return _coll ?? (_coll = GetComponentInChildren<BoxCollider>()); } }
    public float height { get { return collider.size.y * collider.transform.localScale.y; } }
    public int index { get { return transform.GetSiblingIndex(); } }
    public Vector2Int? coord { get; private set; }
    public bool isFree
    {
        get { return _layer == FREE_LAYER; }
        set { _layer = value ? FREE_LAYER : SETTLED_LAYER; }
    }
    AudioSource _ausrc;
    AudioSource audioSrc { get { return _ausrc ?? (_ausrc = GetComponent<AudioSource>()); } }
    #endregion

    #region Events
    public System.Action<Block> onSettled;
    #endregion

    private void Start()
    {
        var c = Ground.instance.GetCellInfo(transform.position);
        isFree = c == null || !c.isInGrid;
    }

    private void Update()
    {
        if(_layer != gameObject.layer)
        {
            transform.SetLayer(_layer, false);
        }
    }

    #region Move & Put
    public void BeginMove()
    {
        _origPos = transform.position;
        audioSrc.PlayOneShot(_pickUpSfx);
    }

	public void MoveOnGround(Vector3 groundPos, BlockStack stack)
    {
        if (stack != null)
        {
            transform.position = stack.topPos;
        }
        else
        {
            var c = Ground.instance.GetCellInfo(groundPos);
            var moveTo = c.isInGrid ? ComputeStackPos(c) : groundPos;
            transform.position = moveTo;
        }
    }

    public void PutOnGround(Vector3 groundPos, BlockStack stack)
    {
        if (stack == null)
        {
            var c = Ground.instance.GetCellInfo(groundPos);
            if (!c.isInGrid)
            {
                transform.position = _origPos;
                coord = null;
                audioSrc.PlayOneShot(_dropFailSfx);
                return;
            }
            coord = c.coord;
        }
        else
        {
            coord = stack.coord;
        }
        if (coord.HasValue)
        {
            World.instance.AddBlock(coord.Value, this);
            isFree = false;
            audioSrc.PlayOneShot(_dropSuccSfx);
            if (!Game.instance.isInTutorial && onSettled != null) onSettled(this);
        }
    }

    Vector3 ComputeStackPos(CellInfo c)
    {
        var stack = World.instance.GetStack(c.coord);
        if (stack == null) return c.pos;
        return stack.topPos;
    }

    public BlockStack stack { get { return transform.GetComponentInParent<BlockStack>(); } }
    #endregion

    #region Spawn & Kill
    static Dictionary<string, int> _idCounter = new Dictionary<string, int>();
    public static int GetIdNum(string id)
    {
        if (_idCounter.ContainsKey(id)) return ++_idCounter[id];
        _idCounter[id] = 0;
        return 0;
    }

    public static Block Spawn(Block prefab)
    {
        var b= Instantiate(prefab);
        __spawnedBlocks.Add(b);
        return b;
    }

    public static Block Spawn(string id)
    {
        var prefab = Resources.Load<Block>("Blocks/" + id);
        if (prefab == null) return null;
        var b = Spawn(prefab);
        b.id = id;
        b.name = id + GetIdNum(id);
        var dir = Random.Range(0, 4);
        switch (dir)
        {
            case 0:
                b.transform.rotation = Quaternion.identity;
                break;
            case 1:
                b.transform.rotation = Quaternion.Euler(0, 90, 0);
                break;
            case 2:
                b.transform.rotation = Quaternion.Euler(0, 180, 0);
                break;
            case 3:
                b.transform.rotation = Quaternion.Euler(0, 270, 0);
                break;
        }
        return b;
    }

    public void Kill()
    {
        if (_isDestroying) return;
        _isDestroying = true;
        if (stack != null) stack.Remove(this);
        __spawnedBlocks.Remove(this);
        Destroy(gameObject);
    }
    #endregion

    #region Production
    public Res[] Produce()
    {
        var blockData = Database.instance.GetBlockData(id);
        if (blockData == null) return null;
        var ret = new List<Res>();
        var canProduce = true;
        if (!blockData.expense.isEmpty)
        {
            var expenseRes = blockData.expense.MakeRes();
            canProduce = ResManager.instance.IsEnough(new[] { expenseRes });
            if (canProduce)
            {
                ret.Add(expenseRes);
            }
        }
        if (!blockData.income.isEmpty && canProduce) ret.Add(blockData.income.MakeRes());
        return ret.ToArray();
    }
    #endregion

    #region Helpers
    #endregion
}
